import functools
from typing import Callable
from fastapi import FastAPI
from aioredis import Redis
from core.logger import logger
from core.common import register_mysql, sys_cache, code_cache
from tortoise.connection import ConnectionHandler

from models.base_model import OperateLog
from configs.config import DB_MYSQL_CONFIG


class MysqlClientProxy:
    def __init__(self, client):
        self.client = client
        self.request = None

    def __getattr__(self, name):
        attr = getattr(self.client, name)
        if callable(attr) and name in ['execute_query', 'execute_query_dict', 'execute_insert', 'execute_many', 'execute_script']:
            @functools.wraps(attr)
            async def wrapper(*args, **kwargs):
                self.request.state.sqls.append(args[0])
                return await attr(*args, **kwargs)
            return wrapper
        return attr
                
    async def save_sqls(self):
        # Insert the query into the SQL logs table
        log_data = {
            "sql": ("\n" + "=" * 66 + "\n").join(self.request.state.sqls),
            "ip": self.request.client.host,
            "user_id": self.request.state.user_id,
            "target_url": self.request.url.path,
            "user_agent": self.request.headers.get("user-agent"),
            "request_params": self.request.state.request_params,
        }
        logger.warning(self.request.state.sqls)
        await OperateLog.create(**log_data)
        

def _my_create_connection(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return MysqlClientProxy(func(*args, **kwargs))
    return wrapper

ConnectionHandler._create_connection = _my_create_connection(ConnectionHandler._create_connection)

def startup(app: FastAPI) -> Callable:
    """
    FastApi 启动完成事件
    :param app: FastAPI
    :return: start_app
    """
    async def app_start() -> None:
        # APP启动完成后触发
        logger.info("fastapi已启动")
        # 注册数据库
        await register_mysql(app)
        logger.info("MySQL已连接")
        # 注入缓存到app state
        app.state.cache = await sys_cache()
        app.state.code_cache = await code_cache()
        logger.info(f"Redis已连接: {app.state.cache}")
    return app_start


def stopping(app: FastAPI) -> Callable:
    """
    FastApi 停止事件
    :param app: FastAPI
    :return: stop_app
    """
    async def stop_app() -> None:
        # APP停止时触发
        logger.info("fastapi已停止")
        cache: Redis = await app.state.cache
        code: Redis = await app.state.code_cache
        await cache.close()
        await code.close()
        logger.info("Redis已关闭")
    return stop_app